package org.bt.common.config.swagger;

import com.google.common.collect.Lists;
import org.bt.common.constant.CommonConstant;
import org.bt.common.enums.ResponseStatus;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.builders.ResponseBuilder;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.RequestHandlerCombiner;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.spring.wrapper.NameValueExpression;

import java.util.ArrayList;
import java.util.List;

/**
 * Swagger基础配置
 * <p>
 * Created on 2021/8/22
 *
 * @author tongw
 */
public class SwaggerBaseConfig implements WebMvcConfigurer {
    @Value("${spring.application.version}")
    private String appVersion;

    @Value("${spring.profiles.active}")
    private String environment;

    @Value("${spring.application.description}")
    private String title;

    /**
     * 显示swagger-ui.html文档展示页，还必须注入swagger资源：
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    }

    private ApiInfo groupApiInfo() {
        return new ApiInfoBuilder()
                .title(String.format("%s(%s)", title, environment))
                .description("<div style='font-size:16px;color:blue;'>" + title + "API接口文档</div>")
                .version(appVersion)
                .build();
    }


    private ApiKey apiKey() {
        return new ApiKey("token", HttpHeaders.AUTHORIZATION, "header");
    }

    private List<SecurityReference> defaultAuth() {
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        return Lists.newArrayList(
                new SecurityReference("token", authorizationScopes));
    }

    private SecurityContext securityContext() {
        return SecurityContext.builder()
                .securityReferences(defaultAuth())
                .forPaths(PathSelectors.regex("/.*"))
                .build();
    }

    @Bean
    public RequestHandlerCombiner disableRequestHandlerCombiner() {
        return source -> source;
    }

    protected Docket configureVersion(String version) {
        return appendSecurity(configureVersionCore(version));
    }

    private Docket appendSecurity(Docket docket) {
        return docket
                .securityContexts(Lists.newArrayList(securityContext()))
                .securitySchemes(Lists.<SecurityScheme>newArrayList(apiKey()));

    }

    private Docket appendGlobalMessages(Docket docket) {
        List<Response> responseMessages = new ArrayList<>();
        responseMessages.add(new ResponseBuilder().code(ResponseStatus.INVALID_REQUEST.value()).build());
        responseMessages.add(new ResponseBuilder().code(ResponseStatus.UNAUTHORIZED.value()).build());
        responseMessages.add(new ResponseBuilder().code(ResponseStatus.TOO_MANY_REQUESTS.value()).build());
        responseMessages.add(new ResponseBuilder().code(ResponseStatus.INTERNAL_SERVER_ERROR.value()).build());
        responseMessages.add(new ResponseBuilder().code(ResponseStatus.BAD_GATEWAY.value()).build());

        return docket
                .globalResponses(HttpMethod.GET, responseMessages)
                .globalResponses(HttpMethod.POST, responseMessages)
                .globalResponses(HttpMethod.PUT, responseMessages)
                .globalResponses(HttpMethod.PATCH, responseMessages)
                .globalResponses(HttpMethod.DELETE, responseMessages);
    }

    protected Docket configureVersionCore(String version) {
        Docket docket = new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(groupApiInfo())
                .groupName(title + "_" + version)
                .select()
                .apis(p -> {
                    if (!p.findControllerAnnotation(RestController.class).isPresent()) {
                        return false;
                    }
                    if (p.headers() != null) {
                        for (NameValueExpression<String> nve : p.headers()) {
                            if ((nve.getName().equals(CommonConstant.ApiVersion.API_VERSION))
                                    && (nve.getValue().equals(version))) {
                                return true;
                            }
                        }
                    }
                    return false;
                })
                .paths(PathSelectors.any())
                .build();

        return appendGlobalMessages(docket);
    }

    protected Docket configurePackageCore(String name, String path) {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(groupApiInfo())
                .groupName(title + " " + name)
                .select()
                .apis(RequestHandlerSelectors.basePackage(path))
                .paths(PathSelectors.any())
                .build();
    }

    protected Docket configurePackage(String name, String path) {
        return appendSecurity(configurePackageCore(name, path));
    }
}
